﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace Lswweb.Domain.ResourceConfiguration
{
    [Serializable]
    public abstract class ResourceBase<TKey, TValue> : IResource, IEnumerable<KeyValuePair<TKey, TValue>>
    {
        private IDictionary<TKey, TValue> sources=null;
        private string filePath;
        private bool isLoaded;

        private object lockThis=new object();
        
        public ResourceBase(string filePath)
        {
            this.filePath = filePath;
            this.sources = new Dictionary<TKey, TValue>();
            this.isLoaded = false;
        }

        #region IResource

        public TValue this[TKey key]
        {
            get 
            {
                EnsureLoadResource();

                TKey result = KeyHandler(key);

                if (!this.sources.ContainsKey(result))
                    throw new InvalidOperationException(string.Format("关键字：{0}不存在于资源文件{1}中", result.ToString(), this.ResourceFilePath));

                return (TValue)this.sources[result]; 
            }
            set
            {
                EnsureLoadResource();

                this.UpdateKeyValuePair(key, value);
            }
        }
        public object this[object key]
        {
            get { return this[(TKey)key]; }
            set { this[(TKey)key] = (TValue)value; }
        }


        public string ResourceFilePath
        {
            get { return this.filePath; }
        }

        public int Count
        {
            get { return this.sources.Count; }
        }

        public bool ContainsKey(TKey key)
        {
            return this.sources.ContainsKey(key);
        }
        public bool ContainsKey(object key)
        {
            return ContainsKey((TKey)key);
        }

        public void Save()
        {
            throw new InvalidOperationException();
        }

        #endregion

        #region IEnumerator<TKey,TValue>

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            EnsureLoadResource();
            return this.sources.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            EnsureLoadResource();
            return this.sources.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// 本方法不要放在构造方法里边
        /// 因为构造方法的执行顺序是先ResourceBase的构造方法，再执行继承类的构造方法
        /// 如果这个方法放置于构造方法，那么在继承类中重载的abstract GetPairByXmlNode方法如果调用一些在子类的构造方法中初始化的对像，将会报错。
        /// 因为LoadResource方法将先于子类的构造方法执行
        /// </summary>
        private void EnsureLoadResource()
        {
            if (this.CanLoadResourceFile())
            {
                ///线程锁定
                lock (this.lockThis)
                {
                    if (this.CanLoadResourceFile())
                    {

                        XmlDocument d = new XmlDocument();
                        d.Load(this.filePath);

                        foreach (XmlNode n in d.SelectSingleNode("root").ChildNodes)
                        {
                            if (n.NodeType == XmlNodeType.Comment)
                                continue;

                            KeyValuePair<TKey, TValue> pair = GetPairByXmlNode(n);

                            this.UpdateKeyValuePair(pair);
                        }

                        isLoaded = true;
                    }
                }
            }
        }

        private bool CanLoadResourceFile()
        {
            return !this.isLoaded && File.Exists(this.filePath);
        }

        private void UpdateKeyValuePair(TKey key, TValue value)
        {
            this.UpdateKeyValuePair(
                new KeyValuePair<TKey, TValue>(key, value));
        }
        private void UpdateKeyValuePair(KeyValuePair<TKey, TValue> pair)
        {
            TKey key = KeyHandler(pair.Key);

            if (this.sources.ContainsKey(key))
                this.sources.Remove(key);

            this.sources.Add(key, pair.Value);
        }
        /// <summary>
        /// 对Tkey进行处理
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private TKey KeyHandler(TKey key)
        {
            //如果key是字符型，那么就把它转换为小写状态，使其不进行大小写区分
            if (key is string)
                return (TKey)Convert.ChangeType(key.ToString().ToLower(),typeof(TKey));

            return key;
        }

        protected abstract KeyValuePair<TKey, TValue> GetPairByXmlNode(XmlNode node);
    }
}
